#include "TempSensor.h"

#include "Tools.h"

typedef enum
{
        TEMP_SENSOR_RW_TYPE_READ,
        TEMP_SENSOR_RW_TYPE_WRITE,
} TempSensorRWType;

struct _TempSensor
{
        GPIO_InitTypeDef gpio;
        GPIO_TypeDef    *gpiox;
};

static TempSensor global_temp_sensor[2];

static void
temp_sensor_write_level(const TempSensor *self, const uint8_t level)
{
        if (level)
                GPIO_SetBits(self->gpiox, self->gpio.GPIO_Pin);
        else
                GPIO_ResetBits(self->gpiox, self->gpio.GPIO_Pin);
}

static uint8_t
temp_sensor_read_level(const TempSensor *self)
{
        return GPIO_ReadInputDataBit(self->gpiox, self->gpio.GPIO_Pin);
}

/**
 * @brief 设置是从温度传感器读取数据还是写入数据
 */
static void
temp_sensor_set_rw_type(TempSensor *self, const TempSensorRWType type)
{
        if (type == TEMP_SENSOR_RW_TYPE_WRITE) {
                self->gpio.GPIO_Mode = GPIO_Mode_Out_PP;
                GPIO_Init(self->gpiox, &self->gpio);
        } else {
                self->gpio.GPIO_Mode = GPIO_Mode_IPU;
                GPIO_Init(self->gpiox, &self->gpio);
        }
}

static void
temp_sensor_reset(TempSensor *self)
{
        temp_sensor_set_rw_type(self, TEMP_SENSOR_RW_TYPE_WRITE);
        temp_sensor_write_level(self, 0);
        delay_us(750);
        temp_sensor_write_level(self, 1);
        delay_us(15);
}

/**
 * @brief 检测传感器返回的存在脉冲
 */
static uint8_t
temp_sensor_detect_pulse(TempSensor *self)
{
        u8 pulse_time = 0;
        temp_sensor_set_rw_type(self, TEMP_SENSOR_RW_TYPE_READ);

        while (temp_sensor_read_level(self) && pulse_time < 100) {
                pulse_time += 1;
                delay_us(1);
        }

        if (pulse_time >= 100) // 经过100us后，存在脉冲都还没有到来
                return 1;      // 读取失败
                               // 经过100us后，存在脉冲到来
        pulse_time = 0;
        // 清零计时变量

        while (!temp_sensor_read_level(self) && pulse_time < 240) {
                pulse_time += 1;
                delay_us(1);
        }
        if (pulse_time >= 240) // 存在脉冲到来，且存在的时间超过了240us
                return 1;      // 读取失败
        return 0;
}

static uint8_t
temp_sensor_read_bit(TempSensor *self)
{
        temp_sensor_set_rw_type(self, TEMP_SENSOR_RW_TYPE_WRITE);
        temp_sensor_write_level(self, 0);
        delay_us(10);

        temp_sensor_set_rw_type(self, TEMP_SENSOR_RW_TYPE_READ);
        uint8_t bit = temp_sensor_read_level(self);
        delay_us(45);

        return bit;
}

static uint8_t
temp_sensor_read_byte(TempSensor *self)
{
        uint8_t byte = 0;
        for (int i = 0, j = 0; i < 8; ++i) {
                j = temp_sensor_read_bit(self);
                byte |= j << i;
        }
        return byte;
}

static void
temp_sensor_write_byte(TempSensor *self, uint8_t byte)
{
        temp_sensor_set_rw_type(self, TEMP_SENSOR_RW_TYPE_WRITE);

        for (int i = 0; i < 8; ++i) {
                if (byte & 0x01) {
                        temp_sensor_write_level(self, 0);
                        delay_us(8);
                        temp_sensor_write_level(self, 1);
                        delay_us(58);
                } else {
                        temp_sensor_write_level(self, 0);
                        delay_us(70);
                        temp_sensor_write_level(self, 1);
                        delay_us(2);
                }
                byte >>= 1;
        }
}

float
temp_sensor_get_temp(TempSensor *self)
{
        float temp_f;

        temp_sensor_reset(self);
        temp_sensor_detect_pulse(self);
        temp_sensor_write_byte(self, 0xcc);
        temp_sensor_write_byte(self, 0x44);

        delay_ms(110);

        temp_sensor_reset(self);
        temp_sensor_detect_pulse(self);
        temp_sensor_write_byte(self, 0xcc);
        temp_sensor_write_byte(self, 0xbe);

        int16_t temp_s = temp_sensor_read_byte(self);
        *(uint16_t *)&temp_s |= temp_sensor_read_byte(self) << 8;

        if (temp_s < 0)
                temp_f = (float)(~temp_s + 1) * 0.0625f;
        else
                temp_f = (float)temp_s * 0.625f;

        return temp_f / 10.0f;
}

TempSensor *
temp_sensor_new_from_global(const uint8_t index)
{
        TempSensor *t = NULL;
        if (index == 0) {
                t                = &global_temp_sensor[0];
                t->gpio.GPIO_Pin = GPIO_Pin_0;
                t->gpiox         = GPIOB;
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        } else {
                t                = &global_temp_sensor[1];
                t->gpio.GPIO_Pin = GPIO_Pin_4;
                t->gpiox         = GPIOA;
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        }

        t->gpio.GPIO_Speed = GPIO_Speed_50MHz;
        t->gpio.GPIO_Mode  = GPIO_Mode_Out_PP;

        GPIO_Init(t->gpiox, &t->gpio);

        temp_sensor_reset(t);
        if (!temp_sensor_detect_pulse(t)) {
                temp_sensor_reset(t);
                temp_sensor_detect_pulse(t);
                temp_sensor_write_byte(t, 0xcc);
                temp_sensor_write_byte(t, 0x44);
                /* 9bit 采样 */
                temp_sensor_write_byte(t, 0x00);
                temp_sensor_write_byte(t, 0x00);
                temp_sensor_write_byte(t, 0x1f);
        }
        return t;
}
